<?php


namespace app\admin\http\middleware;


use app\admin\annotation\ActionLog;
use app\admin\annotation\NoAuth;
use app\admin\annotation\NoLogin;
use app\admin\annotation\UseAuth;
use app\admin\event\AdminActionLogEvent;
use Doctrine\Common\Annotations\AnnotationReader;
use ke\auth\exception\AuthException;
use ke\auth\logic\Auth;
use think\facade\Log;
use think\Request;
use think\Response;

class AnnotationMiddleware
{
    protected $keys = [
        'admin/Config/index'=>'Setting',
    ];

    public function handle(Request $request, callable $next)
    {
        $namespace = 'app\\' . $request->module() . '\\controller\\';
        if (strpos($request->controller(), '.') === false) {
            $namespace .= $request->controller() . 'Controller';
        } else {
            $temps = explode('.', $request->controller());
            $cname = array_pop($temps);
            $namespace .= implode('\\', array_map('strtolower', $temps)) . '\\';
            $namespace .= $cname . 'Controller';
        }

        try {

            $reflectionClass = new \ReflectionClass($namespace);

            // 过滤route注解
            AnnotationReader::addGlobalIgnoredName('route');
            $reader = new AnnotationReader();

            // 登陆注解
            $res = $this->loginCheck($request, $next, $reflectionClass, $reader);
            if (!$res) {
                return $next($request);
            }
            $auth = Auth::instance();
            try {
                $auth->init();

                $request->isLogin = true;
            } catch (AuthException $e) {
                return response()->code(401);
            }

            // 权限注解
            if ($request->isLogin) {
                $res = $this->authPolicy($request, $next, $reflectionClass, $reader);
                if ($res instanceof Response) {
                    return $res;
                }
            }

        } catch (\ReflectionException $e) {
            Log::record('annotation:' . $e->getMessage(), 'error');
        }

        return $next($request);
    }


    /**
     * 是否校验登陆
     * @param Request $request
     * @param callable $next
     * @param \ReflectionClass $reflectionClass
     * @param AnnotationReader $reader
     * @return bool
     * @throws \ReflectionException
     */
    private function loginCheck($request, $next, $reflectionClass, $reader)
    {
        $method = $reflectionClass->getMethod($request->action());

        $annotation = $reader->getClassAnnotation($reflectionClass, NoLogin::class);
        if ($annotation) {
            return false;
        }
        $annotation = $reader->getMethodAnnotation($method, NoLogin::class);

        if ($annotation) {
            return false;
        }
        return true;
    }


    /**
     * 权限注解
     * @param Request $request
     * @param callable $next
     * @param \ReflectionClass $reflectionClass
     * @param AnnotationReader $reader
     * @throws \ReflectionException
     * @return Response
     */
    private function authPolicy($request, $next, $reflectionClass, $reader)
    {
        $method = $reflectionClass->getMethod($request->action());

        // 不需要校验方法
        $annotation = $reader->getMethodAnnotation($method, NoAuth::class);
        if ($annotation) {
            return $next($request);
        }

        // 校验权限
        $annotation = $reader->getClassAnnotation($reflectionClass, UseAuth::class);
        if (!$annotation) {
            $annotation = $reader->getMethodAnnotation($method, UseAuth::class);
        }

        if ($annotation) {
            $user = Auth::instance()->getInfo();

            try {
                $user->hasAuth($annotation->policy);
            } catch (AuthException $e) {
                return json(['status'=>0, 'message'=>$e->getMessage()], 403);
            }
        }
    }

}